#ifndef __MY_DATA__
#define __MY_DATA__
#include<string>
#include"util.hpp"
#include"config.hpp"
#include<pthread.h>
#include<iostream>
#include<unordered_map>
#include<vector>
#include"jsoncpp/json/json.h"
namespace cloud
{
    struct BackupInfo
    {

        bool NewBackupInfo(const std::string& realpath)
        {
            FileUtil file(realpath);
            if(file.Exists()==false)
            {
                std::cout<<"New backupInfo not file"<<std::endl;
                return false;
            }
            pack_flag=false;
            fsize=file.FileSize();
            atime=file.LastATime();
            mtime=file.LastMTime();
            real_path=realpath;
            pack_path=Config::GetInstance()->GetPackDir()+file.FileName()+Config::GetInstance()->GetPackSuffix();
            url=Config::GetInstance()->GetDownloadPrefix()+file.FileName();

            return true;
        }

        bool pack_flag;
        size_t fsize;
        time_t atime;
        time_t mtime;
        std::string real_path;
        std::string pack_path;
        std::string url;
    };

    class DataManager
    {
    public:
        DataManager()
        {
            _backup_file=Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&_mutex,nullptr);
            InitLoad();

        }

        ~DataManager()
        {
            pthread_rwlock_destroy(&_mutex);
        }

        bool Insert(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_mutex);
            _table[info.url]=info;
            pthread_rwlock_unlock(&_mutex);
            Storage();
            return true;
        }

        bool Update(const BackupInfo& info)
        {
            pthread_rwlock_wrlock(&_mutex);
            _table[info.url]=info;
            pthread_rwlock_unlock(&_mutex);
            Storage();
            return true;
        }

        bool GetOneByURL(const std::string& url,BackupInfo* info)
        {
            pthread_rwlock_wrlock(&_mutex);
            auto it=_table.find(url);
            if(it==_table.end())
            {
                pthread_rwlock_unlock(&_mutex);
                return false;
            }
            *info=it->second;
            pthread_rwlock_unlock(&_mutex);
            return true;
        }

        bool GetOneByRealPath(const std::string& realpath,BackupInfo* info)
        {
            pthread_rwlock_wrlock(&_mutex);
            for(auto e:_table)
            {
                if(e.second.real_path==realpath)
                {
                    *info=e.second;
                    pthread_rwlock_unlock(&_mutex);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_mutex);
            return false;
        } 

        bool GetAll(std::vector<BackupInfo>* arr)
        {
            pthread_rwlock_wrlock(&_mutex);
            for(auto e:_table)
            {
                arr->push_back(e.second);
            }
            pthread_rwlock_unlock(&_mutex);
            return true;
        }

        bool Storage()
        {
            std::vector<BackupInfo> arr;
            GetAll(&arr);
            Json::Value root;
            for(int i=0;i<arr.size();i++)
            {
                Json::Value item;
                item["pack_flag"]=arr[i].pack_flag;
                item["atime"]=arr[i].atime;
                item["mtime"]=arr[i].mtime;
                item["fsize"]=arr[i].fsize;
                item["real_path"]=arr[i].real_path;
                item["pack_path"]=arr[i].pack_path;
                item["url"]=arr[i].url;

                root.append(item);

            }
            std::string body;
            if(JsonUtil::Serialize(root,&body)==false)
            {
                std::cout<<"storage:serialize error"<<std::endl;
                return false;
            }
            FileUtil file(_backup_file);
            if(file.SetContent(body)==false)
            {
                std::cout<<"storage:setcontent error\n";
                return false;
            }

            return true;
        }

        bool InitLoad()
        {
            FileUtil file(_backup_file);
            if(file.Exists()==false)
            {
                return true;
            }
            std::string body;
            file.GetContent(&body);
            Json::Value root;
            if(JsonUtil::UnSerialize(body,&root)==false)
            {
                std::cout<<"InitLoad: unserialize"<<std::endl;
                return false;
            }
            for(int i=0;i<root.size();i++)
            {
                BackupInfo info;
                info.pack_flag=root[i]["pack_flag"].asBool();
                info.atime=root[i]["atime"].asInt64();
                info.mtime=root[i]["mtime"].asInt64();
                info.fsize=root[i]["fsize"].asInt64();
                info.pack_path=root[i]["pack_path"].asString();
                info.real_path=root[i]["real_path"].asString();
                info.url=root[i]["url"].asString();

                Insert(info);
            }

            return true;
        }
    private:
        std::string _backup_file;
        std::unordered_map<std::string,BackupInfo> _table;
        pthread_rwlock_t _mutex;
    };
}


#endif